//
//  CartesianTopology.cpp
//  PIDAMRX
//
//  Created by Patrick Zulian on 4/7/11.
//  Copyright 2011 ICS - USI - Lugano. All rights reserved.
//


#include "CartesianTopology.h"
#include "Array.h"
namespace nsesolver {
    namespace mpi {
        
         void CartesianTopology::init()
        {
            const int dim = dimensions.size();
            
            Array< int > periods(dim);
            periods.allSet(0); coordinates.allSet(0);
            
            
            NSE_SOLVER_CATCH_ERROR(MPI_Cart_create(communicator.getMPIComm(), dim, &dimensions[0], &periods[0], false, &cartComm));
            
            this->communicator.setMPIComm(cartComm);
            
            int rank;
            NSE_SOLVER_CATCH_ERROR(MPI_Comm_rank(cartComm, &rank));
            NSE_SOLVER_CATCH_ERROR(MPI_Cart_coords(cartComm, rank, dim, &coordinates[0]));
            
            NSE_SOLVER_ASSERT(rank == communicator.getRank());
            
            for (int d = 0; d < dim; d++) {
                Array< int > dir(dim);
                dir.allSet(0);
                dir[d] = 1;
                int source = rank, dest = 0;
                NSE_SOLVER_CATCH_ERROR(MPI_Cart_shift(cartComm, d, 1, &source, &dest));
                if (!Communicator::isNull(dest)) {
                    neighbors.push_back(Neighbor(d, 1, dest));
                }
                
                NSE_SOLVER_CATCH_ERROR(MPI_Cart_shift(cartComm, d, -1, &source, &dest));
                if (!Communicator::isNull(dest)) {
                    neighbors.push_back(Neighbor(d, -1, dest));
                }
                
            }

        }
        
        
        CartesianTopology::CartesianTopology(const Array< int > &dimensions, const Communicator &communicator)
        : communicator(communicator), cartComm(communicator.getMPIComm()), neighbors(), dimensions(dimensions), coordinates(dimensions.size())
        {
            init();
        }
        
        
        CartesianTopology::CartesianTopology( const int dim, const Communicator &communicator )
        : communicator(communicator), cartComm(communicator.getMPIComm()), neighbors(), dimensions(dim), coordinates(dim)//, realCoords(dim)
        {
            
            dimensions.allSet(0);
            NSE_SOLVER_CATCH_ERROR(MPI_Dims_create(communicator.size(), dim, &dimensions[0]));
            init();
        }
        
   
        
        CartesianTopology::CartesianTopology(const CartesianTopology &other)
        : communicator(other.communicator), cartComm(other.cartComm), neighbors(other.neighbors), dimensions(other.dimensions), coordinates(other.coordinates)
        {
            
        }
        
        CartesianTopology & CartesianTopology::operator = (const CartesianTopology &other)
        {
            if (this == &other) {
                return *this;
            }
            
            communicator = other.communicator;
            cartComm = other.cartComm;
            neighbors = other.neighbors;
            dimensions = other.dimensions;
            coordinates = other.coordinates;
            return *this;
        }
        
        CartesianTopology::~CartesianTopology()
        { }
        
    }
}

